package com.rightrule.rule.executor.rule;

import com.googlecode.aviator.Expression;
import com.rightrule.rule.compile.*;
import com.rightrule.rule.constans.ScriptTypeEnum;
import com.rightrule.rule.dto.DecisionRuleDTO;
import com.rightrule.rule.executor.RuntimeContext;
import com.rightrule.rule.response.BaseExecutionResponse;
import com.rightrule.rule.response.NodeExecutionResponse;
import com.rightrule.rule.utils.ScriptUtils;
import groovy.lang.GroovyObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Objects;


@Data
@Slf4j
public abstract class BaseRule implements Executable, Compilable {
    private Long id;
    private String ruleCode;
    private String ruleName;
    private Integer executeType;
    private String scriptData;
    private String resultData;
    private String defaultResult;

    private transient CompilableInstance compilableInstance;

    @Override
    public CompilableInstance compile() {
        log.debug("rule compile start ,ruleId={}", id);

        if (ScriptTypeEnum.Aviator.getCode().equals(executeType)) {
            Expression expression = ScriptUtils.compileAviatorScript(getScriptData());
            setCompilableInstance(new AviatorCompiledInstance(expression));
            getCompilableInstance();

        } else if (ScriptTypeEnum.Groovy.getCode().equals(executeType)) {
            GroovyObject groovyObject = ScriptUtils.compileGroovyScriptAndGet(getScriptData());
            setCompilableInstance(new GroovyCompiledInstance(groovyObject));
            return getCompilableInstance();

        }
        return null;
    }

    /**
     * 执行规则得到NodeExecutionResponse
     *
     * @param context
     * @param varibleMap
     * @return
     */
    @Override
    public NodeExecutionResponse execute(final RuntimeContext context,
                                         final Map<String, Object> varibleMap) {

        NodeExecutionResponse response = new NodeExecutionResponse();

        try {
            if (this.compilableInstance == null) {
                compile();
            }
        } catch (Exception e) {
            log.error("compile rule error,ruleId={},seq={},errMsg={}", id, context, e);
        }

        BaseExecutionResponse ruleExecuteReq = executeAndGet(context, varibleMap);
        // 设置跑的规则，可以理解为流水
        DecisionRuleDTO exeCuteRule = new DecisionRuleDTO();
        exeCuteRule.setRuleName(ruleName);
        exeCuteRule.setRuleCode(ruleCode);
        exeCuteRule.setId(id);
        exeCuteRule.setExecuteType(executeType);
        response.setExecRule(exeCuteRule);

        // 移除value为空的输出信息和是否命中信息
        if (ruleExecuteReq.getOutput() != null && !ruleExecuteReq.getOutput().isEmpty()) {
            ruleExecuteReq.getOutput().values().removeIf(Objects::isNull);
        }

        response.setExecuteStaus(ruleExecuteReq.getExecuteStaus());
        response.setOutput(ruleExecuteReq.getOutput());
        response.setIsHit(ruleExecuteReq.getIsHit());

        return response;
    }

    /**
     * 执行并且得到BaseExecutionResponse
     *
     * @param context
     * @param varibleMap
     * @return
     */
    abstract BaseExecutionResponse executeAndGet(final RuntimeContext context, final Map<String, Object> varibleMap);
}
